#include "swpreporteditor.h"

#include "../documents/data/reportdata.h"
#include "components/activityexecutionview.h"

#include <bignumbers.h>
#include <idocument.h>
#include <ilinkeddocument.h>

#include <QtGui/QGridLayout>
#include <QtGui/QLabel>

#include <QtGui/QStandardItemModel>

using namespace bignumbers;
using namespace core;
using namespace swp;

SwpReportEditor::SwpReportEditor(QWidget* parent) : QFrame(parent), IEditor(),
    m_focusListeners(),
    m_document(),
    m_documentData(0)
{

}

SwpReportEditor::~SwpReportEditor()
{

}

void SwpReportEditor::open(const QSharedPointer<IDocument>& document)
{
    m_document = document;

    m_documentData = dynamic_cast<ReportData* >(document->data());

    QGridLayout* layout = new QGridLayout(this);
    layout->setContentsMargins(20, 20, 20, 20);

    buildReport(layout);

    setLayout(layout);
}

void SwpReportEditor::close(const QSharedPointer<IDocument>& document)
{

}

QSharedPointer<IDocument> SwpReportEditor::document() const
{
    return m_document;
}

QWidget* SwpReportEditor::widget() const
{
    return const_cast<SwpReportEditor* >(this);
}

QStringList SwpReportEditor::galleryGroups() const
{
    QStringList ret;

    return ret;
}

QList<GalleryItem> SwpReportEditor::galleryItems(const QString& group) const
{
    QList<GalleryItem> ret;

    return ret;
}

void SwpReportEditor::registerFocusListener(QObject* object)
{
    if (!m_focusListeners.contains(object))
    {
        m_focusListeners.append(object);
    }
}

void SwpReportEditor::unregisterFocusListener(QObject* object)
{
    if (m_focusListeners.contains(object))
    {
        m_focusListeners.removeAll(object);
    }
}

IEditor* SwpReportEditor::copy() const
{
    return new SwpReportEditor();
}

void SwpReportEditor::buildReport(QGridLayout* layout)
{
    bool success = true;
    QList<int> runsWithFailure;

    int currentRun = 1;

    for (int i = 0; i < m_documentData->m_tokens->rowCount(); ++i)
    {
        if (m_documentData->m_tokens->item(i, 0)->text().toInt() > currentRun)
        {
            ++currentRun;
        }

        if (m_documentData->m_tokens->item(i, 3)->text().toInt() == 1)
        {
            if (m_documentData->m_tokens->item(i, 2)->text() == "{}")
            {
                success = false;

                if (!runsWithFailure.contains(currentRun))
                {
                    runsWithFailure.append(currentRun);
                }
            }
        }
        else
        {
            if (m_documentData->m_tokens->item(i, 2)->text() != "{}")
            {
                success = false;

                if (!runsWithFailure.contains(currentRun))
                {
                    runsWithFailure.append(currentRun);
                }
            }
        }
    }

    QLabel* status = new QLabel(QString("%1").arg(
        success ? tr("Success") : tr("Failure with %1 runs failed").arg(
            runsWithFailure.size())));
    status->setStyleSheet(
        QString("QLabel { font-size: 25px; font-weight: bold; "
            "color: %1;}").arg(success ? "green" : "red"));

    layout->addWidget(status, 0, 0);

    QSharedPointer<ILinkedDocument> _document =
        qSharedPointerDynamicCast<ILinkedDocument>(m_document);

    Q_ASSERT(!_document.isNull() &&
        _document->links().size() == 1); // can't happen

    const QString labelCss = "QLabel { font-size: 15px; color: gray; }";
    const QString valueCss = "QLabel { font-size: 15px; font-weight: bold; }";

    QLabel* repForL = new QLabel(tr("Report for:"));
    repForL->setStyleSheet(labelCss);
    QLabel* repFor = new QLabel(_document->links().first()->name());
    repFor->setStyleSheet(valueCss);

    layout->addWidget(repForL, 1, 0, Qt::AlignLeft);
    layout->addWidget(repFor, 1, 1, Qt::AlignLeft);
    layout->addItem(new QSpacerItem(0, 0,
        QSizePolicy::Expanding, QSizePolicy::Minimum), 1, 2);

    QLabel* genL = new QLabel(tr("Generated:"));
    genL->setStyleSheet(labelCss);
    QLabel* gen = new QLabel(m_documentData->m_timeStamp);
    gen->setStyleSheet(valueCss);

    layout->addWidget(genL, 2, 0, Qt::AlignLeft);
    layout->addWidget(gen, 2, 1, Qt::AlignLeft);
    layout->addItem(new QSpacerItem(0, 0,
        QSizePolicy::Expanding, QSizePolicy::Minimum), 2, 2);

    currentRun = 1;

    BigInt totalCost;
    BigInt runDuration;
    BigInt totalDuration;

    QHash<QString, QList<BigInt> > activityDetail;
    QHash<QString, QList<BigFloat> > activityDetailAverages;

    for (int i = 0; i < m_documentData->m_executions->rowCount(); ++i)
    {
        if (m_documentData->m_executions->item(
            i, 0)->text().toInt() > currentRun)
        {
            ++currentRun;

            totalDuration = totalDuration + runDuration;
            runDuration = BigInt("0");
        }

        BigInt cost = BigInt(m_documentData->m_executions->item(i, 2)->text());

        QStandardItem* executions = m_documentData->m_executions->item(i, 3);

        BigInt duration;

        for (int j = 0; j < executions->columnCount(); ++j)
        {
            const QString val = executions->child(0, j)->text();
            duration = duration + BigInt(val);
        }

        BigInt columnCount = BigInt(QString::number(
            executions->columnCount()));

        totalCost = totalCost + (cost * columnCount);
        runDuration = runDuration + duration;

        const QString name = m_documentData->m_executions->item(i, 1)->text();

        if (activityDetail.contains(name))
        {
            QList<BigInt>& act = activityDetail[name];

            act[0] = act[0] + columnCount;
            act[1] = act[1] + (cost * columnCount);
            act[2] = act[2] + duration;
        }
        else
        {
            QList<BigInt> act;

            act.append(columnCount);
            act.append((cost * columnCount));
            act.append(duration);

            activityDetail[name] = act;
        }
    }

    if (currentRun == 1)
    {
        totalDuration = runDuration;
    }

    BigFloat runs = BigFloat(QString::number(currentRun));

    BigFloat averageCost = BigFloat(totalCost) / runs;
    BigFloat averageDuration = BigFloat(totalDuration) / runs;

    foreach (const QString& activity, activityDetail.keys())
    {
        QList<BigInt>& detail = activityDetail[activity];

        QList<BigFloat> detailAvgs;

        detailAvgs.append((BigFloat(detail[0]) / runs));
        detailAvgs.append((BigFloat(detail[1]) / runs));
        detailAvgs.append((BigFloat(detail[2]) / runs));

        activityDetailAverages[activity] = detailAvgs;
    }

    layout->addItem(new QSpacerItem(20, 15,
        QSizePolicy::Minimum, QSizePolicy::Minimum), 3, 0);

    QLabel* totCL = new QLabel(tr("Total cost:"));
    totCL->setStyleSheet(labelCss);
    QLabel* totC = new QLabel(totalCost.toString());
    totC->setStyleSheet(valueCss);

    layout->addWidget(totCL, 4, 0, Qt::AlignLeft);
    layout->addWidget(totC, 4, 1, Qt::AlignLeft);
    layout->addItem(new QSpacerItem(0, 0,
        QSizePolicy::Expanding, QSizePolicy::Minimum), 4, 2);

    QLabel* avgCL = new QLabel(tr("Average cost (per run):"));
    avgCL->setStyleSheet(labelCss);
    QLabel* avgC = new QLabel(averageCost.toString(2));
    avgC->setStyleSheet(valueCss);

    layout->addWidget(avgCL, 5, 0, Qt::AlignLeft);
    layout->addWidget(avgC, 5, 1, Qt::AlignLeft);
    layout->addItem(new QSpacerItem(0, 0,
        QSizePolicy::Expanding, QSizePolicy::Minimum), 5, 2);

    layout->addItem(new QSpacerItem(20, 15,
        QSizePolicy::Minimum, QSizePolicy::Minimum), 6, 0);

    QLabel* totDL = new QLabel(tr("Total duration:"));
    totDL->setStyleSheet(labelCss);
    QLabel* totD = new QLabel(totalDuration.toString());
    totD->setStyleSheet(valueCss);

    layout->addWidget(totDL, 7, 0, Qt::AlignLeft);
    layout->addWidget(totD, 7, 1, Qt::AlignLeft);
    layout->addItem(new QSpacerItem(0, 0,
        QSizePolicy::Expanding, QSizePolicy::Minimum), 7, 2);

    QLabel* avgDL = new QLabel(tr("Average duration (per run):"));
    avgDL->setStyleSheet(labelCss);
    QLabel* avgD = new QLabel(averageDuration.toString(2));
    avgD->setStyleSheet(valueCss);

    layout->addWidget(avgDL, 8, 0, Qt::AlignLeft);
    layout->addWidget(avgD, 8, 1, Qt::AlignLeft);
    layout->addItem(new QSpacerItem(0, 0,
        QSizePolicy::Expanding, QSizePolicy::Minimum), 8, 2);

    layout->addItem(new QSpacerItem(20, 15,
        QSizePolicy::Minimum, QSizePolicy::Minimum), 9, 0);

    QLabel* runsL = new QLabel(tr("Runned:"));
    runsL->setStyleSheet(labelCss);
    QLabel* runsV = new QLabel(QString("%1 times").arg(currentRun));
    runsV->setStyleSheet(valueCss);

    layout->addWidget(runsL, 10, 0, Qt::AlignLeft);
    layout->addWidget(runsV, 10, 1, Qt::AlignLeft);
    layout->addItem(new QSpacerItem(0, 0,
        QSizePolicy::Expanding, QSizePolicy::Minimum), 10, 2);

    ActivityExecutionView* act = new ActivityExecutionView();

    foreach (const QString& activity, activityDetail.keys())
    {
        const QList<BigInt>& detail = activityDetail[activity];
        const QList<BigFloat>& detailAvgs = activityDetailAverages[activity];

        act->addActivity(activity, detail[0].toString(),
            detailAvgs[0].toString(2), detail[1].toString(),
            detailAvgs[1].toString(2), detail[2].toString(),
            detailAvgs[2].toString(2));
    }

    layout->addItem(new QSpacerItem(20, 15,
        QSizePolicy::Minimum, QSizePolicy::Minimum), 11, 0);
    layout->addWidget(act, 12, 0, 1, 3);

    //layout->addItem(new QSpacerItem(0, 0,
      //  QSizePolicy::Minimum, QSizePolicy::Expanding), 13, 0);
}
